/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.eleric.rememome.db;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.eleric.rememome.misc.FieldAndValue;
import com.eleric.rememome.misc.FieldAndValueOperator;
import com.eleric.rememome.type.OrderType;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 *
 * @author MWaldman
 */
abstract public class AbstractDbRetriever<T> implements DbRetriever<T>
{

    private String table;

    public AbstractDbRetriever(String table)
    {
        this.table = table;
    }

    public String getTable()
    {
        return table;
    }

    protected String getConditionalString(List<FieldAndValueOperator> fieldValueOperList)
    {
        StringBuffer buf;
        Iterator<FieldAndValueOperator> iter;
        buf = new StringBuffer();

        iter = fieldValueOperList.iterator();
        while (iter.hasNext())
        {
            FieldAndValueOperator fv = iter.next();
            buf.append(fv.getField());
            buf.append(fv.getOperator());
            if (!(fv.getValue() instanceof Number))
            {
                buf.append("'");
                buf.append(fv.getValue().toString());
                buf.append("'");
            }
            else
            {
                buf.append(fv.getValue().toString());
            }
            if (iter.hasNext())
            {
                buf.append(" And ");
            }
        }
        return buf.toString();
    }

    public boolean delete(List<FieldAndValueOperator> fieldValueOperList, SQLiteDatabase db)
    {
        return db.delete(getTable(), getConditionalString(fieldValueOperList), null) > 0;
    }

    protected ContentValues getContentValues(List<FieldAndValue> fieldValues)
    {
        ContentValues initialValues = new ContentValues();
        for (FieldAndValue fv : fieldValues)
        {
            if (fv.getValue() instanceof Boolean)
            {
                initialValues.put(fv.getField(), (Boolean) fv.getValue());
            }
            else if (fv.getValue() instanceof Byte)
            {
                initialValues.put(fv.getField(), (Byte) fv.getValue());
            }
            else if (fv.getValue() instanceof Double)
            {
                initialValues.put(fv.getField(), (Double) fv.getValue());
            }
            else if (fv.getValue() instanceof Float)
            {
                initialValues.put(fv.getField(), (Float) fv.getValue());
            }
            else if (fv.getValue() instanceof Integer)
            {
                initialValues.put(fv.getField(), (Integer) fv.getValue());
            }
            else if (fv.getValue() instanceof Long)
            {
                initialValues.put(fv.getField(), (Long) fv.getValue());
            }
            else if (fv.getValue() instanceof Short)
            {
                initialValues.put(fv.getField(), (Short) fv.getValue());
            }
            else if (fv.getValue() instanceof byte[])
            {
                initialValues.put(fv.getField(), (byte[]) fv.getValue());
            }
            else
            {
                initialValues.put(fv.getField(), fv.getValue().toString());
            }
        }
        return initialValues;
    }

    public long insert(List<FieldAndValue> fieldValues, SQLiteDatabase db)
    {
        ContentValues initialValues;

        initialValues = getContentValues(fieldValues);

        return db.insert(getTable(), null, initialValues);
    }

    public boolean update(List<FieldAndValue> fieldValueList,
            List<FieldAndValueOperator> fieldValueConditionList, SQLiteDatabase db)
    {
        ContentValues args = new ContentValues();
        String cond;

        args = getContentValues(fieldValueList);
        cond = getConditionalString(fieldValueConditionList);

        return db.update(getTable(), args, cond, null) > 0;
    }

    abstract protected String[] getColumns();

    @Override
    public List<T> list(SQLiteDatabase db)
    {
        return list(null, null, db);
    }

    @Override
    public List<T> list(OrderType orderType, SQLiteDatabase db)
    {
        return list(null, orderType, db);
    }

    @Override
    public List<T> list(List<FieldAndValueOperator> fieldValueOperList, SQLiteDatabase db)
    {
        return list(fieldValueOperList, null, db);
    }

    @Override
    public List<T> list(List<FieldAndValueOperator> fieldValueOperList, OrderType orderType,
            SQLiteDatabase db)
    {
        String order;
        List<T> ts;
        T t;
        Cursor c;
        String conditions;
        ts = new ArrayList<T>();

        if (fieldValueOperList == null)
        {
            conditions = null;
        }
        else if (fieldValueOperList.size() == 0)
        {
            conditions = null;
        }
        else
        {
            conditions = getConditionalString(fieldValueOperList);
        }

        if (orderType == null)
        {
            order = null;
        }
        else
        {
            order = getOrderTypeString(orderType);
        }

        c = db.query(getTable(), getColumns(), conditions, null, null, null, order);

        if (c.moveToFirst())
        {
            t = convertTo(c, db);
            ts.add(t);
        }
        while (c.moveToNext())
        {
            t = convertTo(c, db);
            ts.add(t);
        }
        c.close();
        return ts;
    }

    @Override
    public T get(List<FieldAndValueOperator> fieldValueOperList, SQLiteDatabase db)
    {
        T t;
        Cursor c;

        c = db.query(getTable(), getColumns(), getConditionalString(fieldValueOperList), null, null,
                null, null);
        if (c.moveToFirst())
        {
            t = convertTo(c, db);
        }
        else
        {
            t = null;
        }
        c.close();
        return t;
    }

    abstract protected String getOrderTypeString(OrderType orderType);

    abstract protected T convertTo(Cursor c, SQLiteDatabase db);
}
